<div class="tmd-doc">
<p></p>
<h1 class="tmd-header-1">
Some Undocumented Changes in Go 1.18 and 1.19
</h1>
<p></p>
<div class="tmd-usual">
When a new Go version is released, the changes in this version are generally listed the release notes of the version. However, occasionally, some changes were missing in the release notes.
</div>
<p></p>
<div class="tmd-usual">
This article lists several missing changes in Go <a href="https://go.dev/doc/go1.18">1.18</a> and <a href="https://go.dev/doc/go1.19">1.19</a> release notes.
</div>
<p></p>
<p></p>
<h2 class="tmd-header-2">
GoTV
</h2>
<p></p>
<div class="tmd-usual">
We use GoTV <sup><a id="fn:gotv:ref-1" href="#fn:gotv">[1]</a></sup> to demonstrate the unmentioned changes in this article. GoTV (Go Toolchain Version) is a tool used to manage and use multiple coexisting installations of official Go toolchain versions harmoniously and conveniently.
</div>
<p></p>
<div class="tmd-usual">
If you haven't, you may install GoTV by running
</div>
<p></p>
<pre class="tmd-code">
go install go101.org/gotv@latest
</pre>
<p></p>
<div class="tmd-usual">
then run the following commands to install the latest releases of Go 1.17, Go 1.18 and Go 1.19 toolchains.
</div>
<p></p>
<pre class="tmd-code">
gotv 1.17. version
gotv 1.18. version
gotv 1.19. version
</pre>
<p></p>
<div class="tmd-usual">
The first execution of the <code class="tmd-code-span">gotv</code> command needs to pull the Go language project, so it might need several minutes to finish.
</div>
<p></p>
<h2 class="tmd-header-2">
The definition of the terminology <mark class="tmd-marked">slice of bytes</mark> is clarified
</h2>
<p></p>
<div class="tmd-usual">
Go specification states <mark class="tmd-marked">a non-constant value <code class="tmd-code-span">x</code> can be converted to type <code class="tmd-code-span">T</code> if <code class="tmd-code-span">x</code> is a string and <code class="tmd-code-span">T</code> is a slice of bytes, and vice versa</mark>.
</div>
<p></p>
<div class="tmd-usual">
But what is a <mark class="tmd-marked">slice of bytes</mark>? There are two interpretations:
</div>
<p></p>
<ol class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
any type whose underlying type is <code class="tmd-code-span">[]byte</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
any slice type whose element type's underlying type is <code class="tmd-code-span">byte</code>.
</div>
</li>
</ol>
<p></p>
<div class="tmd-usual">
Before Go 1.18, the official standard Go compiler sometimes adopted the first interpretation, sometimes adopted the second interpretation. Since Go 1.18, the official standard Go compiler always adopts the second interpretation. And Go 1.19 formally admitted the 1.18+ implementation is correct.
</div>
<p></p>
<div class="tmd-usual">
For example, the official standard Go compiler 1.17 thinks the function <code class="tmd-code-span">f</code> in the following code is valid but thinks the function <code class="tmd-code-span">g</code> is invalid.
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

type T byte

//go:noinline
func f(s string) []T {
	return []T(s)
}

//go:noinline
func g(x []T) string {
	return string(x) // error (line 12)
}

func main() {
	_ = f("Go")
	_ = g([]T{71, 111})
}
</code></pre>
<p></p>
<div class="tmd-usual">
Since Go toolchain 1.18, both of the two functions compile okay. The followings are the outputs of the official standard Go compiler 1.17 and 1.18 for the above program.
</div>
<p></p>
<pre class="tmd-code">
$ gotv 1.17. run main.go
[Run]: $HOME/.cache/gotv/tag_go1.17.13/bin/go run main.go
# command-line-arguments
./main.go:12:15: cannot use &lt;node SPTR&gt; (type *T) as type *byte in argument to runtime.slicebytetostring

$ gotv 1.18. run main.go
[Run]: $HOME/.cache/gotv/tag_go1.18.7/bin/go main main.go
</pre>
<p></p>
<div class="tmd-usual">
The official standard Go compiler 1.17 sometimes views <code class="tmd-code-span">[]T</code> as a <mark class="tmd-marked">slice of bytes</mark> (in the function <code class="tmd-code-span">f</code>), sometimes doesn't (in the function <code class="tmd-code-span">g</code>). If the <code class="tmd-code-span">type T byte</code> type definition is changed into a type alias declaration <code class="tmd-code-span">type T = byte</code> , then the function <code class="tmd-code-span">g</code> is also viewed as valid by the official standard Go compiler 1.17.
</div>
<p></p>
<div class="tmd-usual">
The same situation happened for <mark class="tmd-marked">slices of runes</mark> (or <mark class="tmd-marked">rune slice</mark>).
</div>
<p></p>
<div class="tmd-usual">
Note, up to now (Go 1.19), the <code class="tmd-code-span">reflect</code> standard package has not been updated accordingly. For example, the following program prints two <code class="tmd-code-span">false</code>, but should print two <code class="tmd-code-span">true</code> instead.
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

import "reflect"

type T byte

func main() {
	var s string
	var x []T
	var sType = reflect.TypeOf(s)
	var xType = reflect.TypeOf(x)
	println(sType.ConvertibleTo(xType))
	println(xType.ConvertibleTo(sType))
}
</code></pre>
<p></p>
<div class="tmd-usual">
References:
</div>
<p></p>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
<a href="https://github.com/golang/go/issues/23536">https://github.com/golang/go/issues/23536</a>
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
<a href="https://github.com/golang/go/issues/23814">https://github.com/golang/go/issues/23814</a>
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
<a href="https://github.com/golang/go/issues/53523">https://github.com/golang/go/issues/53523</a>
</div>
</li>
</ul>
<p></p>
<h2 class="tmd-header-2">
A subtle detail in local constant declarations
</h2>
<p></p>
<div class="tmd-usual">
What should the following program print?
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

func main() {
	const (
		iota = iota
		Y
	)
	println(Y)
}
</code></pre>
<p></p>
<div class="tmd-usual">
Some gophers think it should print <code class="tmd-code-span">1</code>, which is actually the answer of the official standard Go compiler 1.17.13-. However, since the official standard Go compiler 1.18, the answer is <code class="tmd-code-span">0</code>. The followings are the outputs with different compiler versions:
</div>
<p></p>
<pre class="tmd-code">
$ gotv 1.17. run main.go
[Run]: $HOME/.cache/gotv/tag_go1.17.13/bin/go run main.go
1

$ gotv 1.18. run main.go
[Run]: $HOME/.cache/gotv/tag_go1.18.7/bin/go run main.go
0
</pre>
<p></p>
<div class="tmd-usual">
Which answer is correct?
</div>
<p></p>
<div class="tmd-usual">
The Go specification says:
</div>
<p></p>
<div class="tmd-quotation">
<div class="tmd-usual">
Within a parenthesized const declaration list the expression list may be omitted from any but the first ConstSpec. Such an empty list is equivalent to the textual substitution of the first preceding non-empty expression list and its type if any. Omitting the list of expressions is therefore equivalent to repeating the previous list.
</div>
</div>
<p></p>
<div class="tmd-usual">
The description states the 1.18+ answer is correct, because the above program is equivalent to
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

func main() {
	const (
		iota = iota
		Y    = iota
	)
	println(Y)
}
</code></pre>
<p></p>
<div class="tmd-usual">
The last <code class="tmd-code-span">iota</code> is the local declared <code class="tmd-code-span">iota</code>, which value is <code class="tmd-code-span">0</code>.
</div>
<p></p>
<div class="tmd-usual">
Go 1.19 confirmed it was a bug in 1.17.13- versions.
</div>
<p></p>
<div class="tmd-usual">
Ref: <a href="https://github.com/golang/go/issues/49157">https://github.com/golang/go/issues/49157</a>
</div>
<p></p>
<h2 class="tmd-header-2">
A long-time type alias related bug was fixed
</h2>
<p></p>
<div class="tmd-usual">
With the introduction of type alias in Go 1.8, a comparison bug was also introduced.
</div>
<p></p>
<div class="tmd-usual">
The following program should print <code class="tmd-code-span">false</code>, but it prints <code class="tmd-code-span">true</code> when using the official standard Go compiler from version 1.8 to 1.17.13.
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

type T struct{}
type S = T

type A = struct{ T }
type B = struct{ S }

func main() {
	var a A
	var b B
	println(interface{}(b) == interface{}(a)) 
}
</code></pre>
<p></p>
<div class="tmd-usual">
The type aliases <code class="tmd-code-span">A</code> and <code class="tmd-code-span">B</code> denote different types (with different field names), which is why the comparison should result <code class="tmd-code-span">false</code>.
</div>
<p></p>
<div class="tmd-usual">
The bug was fixed in Go 1.18.
</div>
<p></p>
<div class="tmd-usual">
The followings are the outputs with different compiler versions:
</div>
<p></p>
<pre class="tmd-code">
$ gotv 1.17. run main.go
[Run]: $HOME/.cache/gotv/tag_go1.17.13/bin/go run main.go
true

$ gotv 1.18. run main.go
[Run]: $HOME/.cache/gotv/tag_go1.18.7/bin/go run main.go
false
</pre>
<p></p>
<div class="tmd-usual">
Ref: <a href="https://github.com/golang/go/issues/24721">https://github.com/golang/go/issues/24721</a>
</div>
<p></p>
<h2 class="tmd-header-2">
The <mark class="tmd-marked-2">named type</mark> terminology came back to Go specification
</h2>
<p></p>
<div class="tmd-usual">
With the introduction of type alias in Go 1.8, the <mark class="tmd-marked">named type</mark> terminology was removed from Go specification. A new terminology <mark class="tmd-marked">defined type</mark> was introduced to fill in the gaps caused by the removal of <mark class="tmd-marked">named type</mark>. However, <a href="https://github.com/golang/go/issues/35091">this made many old Go tutorials and articles become obsolete and brought several other drawbacks</a>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
With the introduction of custom generics, the <mark class="tmd-marked">named type</mark> terminology came back since Go 1.18, which is helpful to clearly explain <a href="https://go101.org/article/value-conversions-assignments-and-comparisons.html">many conversion and assignment rules</a> in Go.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Now, a named type may be
</div>
<p></p>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
a predeclared type;
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
a defined (non-custom-generic) type;
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
an instantiated type (of a generic type);
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
a type parameter type (used in custom generics).
</div>
</li>
</ul>
<p></p>
<div class="tmd-usual">
Note, a type alias of an unnamed type is not a named type.
</div>
<p></p>
<h2 class="tmd-header-2">
Goexit signals may cancel already happened (recoverable) panics
</h2>
<p></p>
<div class="tmd-usual">
Should the following program crash for panicking or exit normally?
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

import "runtime"

func main() {
	c := make(chan struct{})
	go func() {
		defer close(c)
		defer runtime.Goexit()
		panic("bye")
	}()
	&lt;-c
}
</code></pre>
<p></p>
<div class="tmd-usual">
Before Go 1.19, there was not a clear answer. Some gophers think it should crash, for the <code class="tmd-code-span">"bye"</code> panic is never recovered. But in the implementation of the official standard Go runtime, a Goexit signal will cancel already happened (recoverable) panics in the current goroutine. So, with the official standard compiler, the above program will exit normally. <a href="https://github.com/golang/go/issues/35378">The behavior was decided as correct in Go 1.19</a>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
In my personal opinion, Goexit signals should not cancel panics, so the above program should crash instead. But I respect the final decision of the Go core team.
</div>
<p></p>
<div class="tmd-usual">
The final decision makes <code class="tmd-code-span">runtime.Goexit</code> calls act as super <code class="tmd-code-span">recover</code> calls. For example, the following two goroutine functions behave the same.
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">func goroutine1() {
	defer runtime.Goexit()
	panic(1)
}

func goroutine2() {
	defer func() {
		recover()
	}()
	panic(1)
}
</code></pre>
<p></p>
<div class="tmd-usual">
The official Go documentation explains the panic/recover mechanism so simply that there are still several other details which don't get covered, which is why the Go 101 book includes <a href="https://go101.org/article/panic-and-recover-more.html">a special article to explain the panic/recover mechanism in detail</a>.
</div>
<p></p>
<p></p>
<h2 class="tmd-header-2">
More small compiler and runtime changes
</h2>
<p></p>
<div class="tmd-usual">
There are also some undocumented small compiler and runtime optimizations made in recent Go toolchain versions. Some of the small optimizations are mentioned in the <a href="https://go101.org/optimizations/101.html">Go Optimizations 101</a> book.
</div>
<p></p>
<p></p>
<hr  class="tmd-seperator"/>
<p></p>

<ol class="tmd-list tmd-footnotes" id="fn:">
<li id="fn:gotv" class="tmd-list-item tmd-footnote-item">
<div id="gotv" class="tmd-usual">
GoTV (<a href="https://go101.org/apps-and-libs/gotv.html">https://go101.org/apps-and-libs/gotv.html</a>) is a tool used to install and use coexisting installations of Go toolchain verisons harmoniously.
</div>
<a href="#fn:gotv:ref-1">↩︎</a></li>
</ol>
</div>
